package com.w.picture.manager.sharding;

import org.apache.shardingsphere.sharding.api.sharding.standard.PreciseShardingValue;
import org.apache.shardingsphere.sharding.api.sharding.standard.RangeShardingValue;
import org.apache.shardingsphere.sharding.api.sharding.standard.StandardShardingAlgorithm;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Properties;

/**
 * 自定义的分片算法
 *
 * @author wzp
 * @since 2025/2/1
 */
public class PictureShardingAlgorithm implements StandardShardingAlgorithm<Long> {
    /**
     * 精确分片策略实现。
     *
     * @param availableTargetNames 可用的目标表名集合，包含所有可能的分表名称。在动态分表的情况下，这个列表需要通过外部管理器来更新。
     * @param shardingValue        分片值，包含分片键的具体值（这里为spaceId）和逻辑表名。
     * @return 返回根据分片键计算出的目标表名。
     */
    @Override
    public String doSharding(Collection<String> availableTargetNames, PreciseShardingValue<Long> shardingValue) {
        Long spaceId = shardingValue.getValue(); // 获取分片键的实际值，即spaceId
        String logicTableName = shardingValue.getLogicTableName(); // 获取逻辑表名，这里是"picture"
        // spaceId 为 null 表示查询所有图片
        if (spaceId == null) {
            return logicTableName;
        }
        // 根据 spaceId 动态生成分表名
        // 注意: 这里的版本代码,在我们的项目中是不能完成动态分表,因为availableTargetNames(可用的分表)始终为逻辑表名 picture.
        // 原因: shardingSphere 在分片逻辑初始化时,默认获取的配置是 actual-data-nodes 的值,而我们一开始配置在那里的是一个固定值 picture
        // 所以,在分片逻辑初始化时,shardingSphere 是没办法根据 spaceId 动态生成分表名
        // 解决的办法:既然框架自身不支持动态维护分表,那我们可以写一个分表管理器,自己来维护分表的列表availableTargetNames,并更新到 shardingSphere 的 actual-data-nodes配置中.
        String tableName = "picture_" + spaceId;
        if (availableTargetNames.contains(tableName)) {
            return tableName;
        } else {
            return logicTableName;
        }
    }

    /**
     * 范围分片策略实现。
     * 注意：此方法在这个例子中未被实际使用，因为我们的分片策略是基于精确匹配的spaceId。
     *
     * @param availableTargetNames 可用的目标表名集合，与doSharding方法中的相同。
     * @param shardingValue        分片范围值，包含分片键的范围条件。
     * @return 返回一个空的集合，因为我们不支持范围查询。
     */
    @Override
    public Collection<String> doSharding(Collection<String> availableTargetNames, RangeShardingValue<Long> shardingValue) {
        return new ArrayList<>();
    }

    /**
     * 获取配置属性。
     * 此方法用于获取自定义分片算法的配置属性。
     *
     * @return 返回配置属性，这里返回null表示没有额外的配置。
     */
    @Override
    public Properties getProps() {
        return null;
    }

    /**
     * 初始化方法。
     * 在ShardingSphere初始化时调用，用于初始化自定义分片算法的配置。
     *
     * @param properties 配置属性。
     */
    @Override
    public void init(Properties properties) {

    }
}
